From: Vijaya Kumar K Date: Fri, 12 Sep 2014 11:09:47 +0000 (+0530) Subject: xen/arm: Update Dom0 GIC dt node with GICv3 information X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~4416 X-Git-Url: https://dgit.raspbian.org/%22http:/www.example.com/cgi/%22https:/%22bookmarks://%22/%22http:/www.example.com/cgi/%22https:/%22bookmarks:/%22?a=commitdiff_plain;h=5dd422c656c6781a4703bb5b681d558d7c199996;p=xen.git xen/arm: Update Dom0 GIC dt node with GICv3 information Update GIC device tree node for DOM0 with GICv3 information. GIC hw specfic device tree information is moved to respective GIC driver. Signed-off-by: Vijaya Kumar K Acked-by: Julien Grall Acked-by: Ian Campbell --- diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c index 2d316dd1fb..90abc3ad12 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -777,9 +777,6 @@ static int make_gic_node(const struct domain *d, void *fdt, const struct dt_device_node *node) { const struct dt_device_node *gic = dt_interrupt_controller; - const void *compatible = NULL; - u32 len; - __be32 *new_cells, *tmp; int res = 0; /* @@ -794,48 +791,7 @@ static int make_gic_node(const struct domain *d, void *fdt, DPRINT("Create gic node\n"); - compatible = dt_get_property(gic, "compatible", &len); - if ( !compatible ) - { - dprintk(XENLOG_ERR, "Can't find compatible property for the gic node\n"); - return -FDT_ERR_XEN(ENOENT); - } - - res = fdt_begin_node(fdt, "interrupt-controller"); - if ( res ) - return res; - - res = fdt_property(fdt, "compatible", compatible, len); - if ( res ) - return res; - - res = fdt_property_cell(fdt, "#interrupt-cells", 3); - if ( res ) - return res; - - res = fdt_property(fdt, "interrupt-controller", NULL, 0); - - if ( res ) - return res; - - len = dt_cells_to_size(dt_n_addr_cells(node) + dt_n_size_cells(node)); - len *= 2; /* GIC has two memory regions: Distributor + CPU interface */ - new_cells = xzalloc_bytes(len); - if ( new_cells == NULL ) - return -FDT_ERR_XEN(ENOMEM); - - tmp = new_cells; - DPRINT(" Set Distributor Base 0x%"PRIpaddr"-0x%"PRIpaddr"\n", - d->arch.vgic.dbase, d->arch.vgic.dbase + PAGE_SIZE - 1); - dt_set_range(&tmp, node, d->arch.vgic.dbase, PAGE_SIZE); - - DPRINT(" Set Cpu Base 0x%"PRIpaddr"-0x%"PRIpaddr"\n", - d->arch.vgic.cbase, d->arch.vgic.cbase + (PAGE_SIZE * 2) - 1); - dt_set_range(&tmp, node, d->arch.vgic.cbase, PAGE_SIZE * 2); - - res = fdt_property(fdt, "reg", new_cells, len); - xfree(new_cells); - + res = gic_make_node(d, node, fdt); if ( res ) return res; @@ -1058,6 +1014,7 @@ static int handle_node(struct domain *d, struct kernel_info *kinfo, static const struct dt_device_match gic_matches[] __initconst = { DT_MATCH_GIC_V2, + DT_MATCH_GIC_V3, { /* sentinel */ }, }; static const struct dt_device_match timer_matches[] __initconst = diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c index 78ad4de7e9..f053b5db96 100644 --- a/xen/arch/arm/gic-v2.c +++ b/xen/arch/arm/gic-v2.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -585,6 +586,55 @@ static void gicv2_irq_set_affinity(struct irq_desc *desc, const cpumask_t *cpu_m spin_unlock(&gicv2.lock); } +static int gicv2_make_dt_node(const struct domain *d, + const struct dt_device_node *node, void *fdt) +{ + const struct dt_device_node *gic = dt_interrupt_controller; + const void *compatible = NULL; + u32 len; + __be32 *new_cells, *tmp; + int res = 0; + + compatible = dt_get_property(gic, "compatible", &len); + if ( !compatible ) + { + dprintk(XENLOG_ERR, "Can't find compatible property for the gic node\n"); + return -FDT_ERR_XEN(ENOENT); + } + + res = fdt_begin_node(fdt, "interrupt-controller"); + if ( res ) + return res; + + res = fdt_property(fdt, "compatible", compatible, len); + if ( res ) + return res; + + res = fdt_property_cell(fdt, "#interrupt-cells", 3); + if ( res ) + return res; + + res = fdt_property(fdt, "interrupt-controller", NULL, 0); + + if ( res ) + return res; + + len = dt_cells_to_size(dt_n_addr_cells(node) + dt_n_size_cells(node)); + len *= 2; /* GIC has two memory regions: Distributor + CPU interface */ + new_cells = xzalloc_bytes(len); + if ( new_cells == NULL ) + return -FDT_ERR_XEN(ENOMEM); + + tmp = new_cells; + dt_set_range(&tmp, node, d->arch.vgic.dbase, PAGE_SIZE); + dt_set_range(&tmp, node, d->arch.vgic.cbase, PAGE_SIZE * 2); + + res = fdt_property(fdt, "reg", new_cells, len); + xfree(new_cells); + + return res; +} + /* XXX different for level vs edge */ static hw_irq_controller gicv2_host_irq_type = { .typename = "gic-v2", @@ -630,6 +680,7 @@ const static struct gic_hw_operations gicv2_ops = { .write_lr = gicv2_write_lr, .read_vmcr_priority = gicv2_read_vmcr_priority, .read_apr = gicv2_read_apr, + .make_dt_node = gicv2_make_dt_node, }; /* Set up the GIC */ diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c index 6ccde02b08..ca450f966c 100644 --- a/xen/arch/arm/gic-v3.c +++ b/xen/arch/arm/gic-v3.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -1027,6 +1028,82 @@ static void gicv3_irq_set_affinity(struct irq_desc *desc, const cpumask_t *mask) spin_unlock(&gicv3.lock); } +static int gicv3_make_dt_node(const struct domain *d, + const struct dt_device_node *node, void *fdt) +{ + const struct dt_device_node *gic = dt_interrupt_controller; + const void *compatible = NULL; + uint32_t len; + __be32 *new_cells, *tmp; + uint32_t rd_stride = 0; + uint32_t rd_count = 0; + + int i, res = 0; + + compatible = dt_get_property(gic, "compatible", &len); + if ( !compatible ) + { + dprintk(XENLOG_ERR, "Can't find compatible property for the gic node\n"); + return -FDT_ERR_XEN(ENOENT); + } + + res = fdt_begin_node(fdt, "interrupt-controller"); + if ( res ) + return res; + + res = fdt_property(fdt, "compatible", compatible, len); + if ( res ) + return res; + + res = fdt_property_cell(fdt, "#interrupt-cells", 3); + if ( res ) + return res; + + res = fdt_property(fdt, "interrupt-controller", NULL, 0); + if ( res ) + return res; + + res = dt_property_read_u32(gic, "redistributor-stride", &rd_stride); + if ( !res ) + rd_stride = 0; + + res = dt_property_read_u32(gic, "#redistributor-regions", &rd_count); + if ( !res ) + rd_count = 1; + + res = fdt_property_cell(fdt, "redistributor-stride", rd_stride); + if ( res ) + return res; + + res = fdt_property_cell(fdt, "#redistributor-regions", rd_count); + if ( res ) + return res; + + len = dt_cells_to_size(dt_n_addr_cells(node) + dt_n_size_cells(node)); + /* + * GIC has two memory regions: Distributor + rdist regions + * CPU interface and virtual cpu interfaces accessesed as System registers + * So cells are created only for Distributor and rdist regions + */ + len = len * (d->arch.vgic.rdist_count + 1); + new_cells = xzalloc_bytes(len); + if ( new_cells == NULL ) + return -FDT_ERR_XEN(ENOMEM); + + tmp = new_cells; + + dt_set_range(&tmp, node, d->arch.vgic.dbase, d->arch.vgic.dbase_size); + + for ( i = 0; i < d->arch.vgic.rdist_count; i++ ) + dt_set_range(&tmp, node, d->arch.vgic.rbase[i], + d->arch.vgic.rbase_size[i]); + + res = fdt_property(fdt, "reg", new_cells, len); + xfree(new_cells); + + return res; +} + static const hw_irq_controller gicv3_host_irq_type = { .typename = "gic-v3", .startup = gicv3_irq_startup, @@ -1071,6 +1148,7 @@ static const struct gic_hw_operations gicv3_ops = { .read_vmcr_priority = gicv3_read_vmcr_priority, .read_apr = gicv3_read_apr, .secondary_init = gicv3_secondary_cpu_init, + .make_dt_node = gicv3_make_dt_node, }; /* Set up the GIC */ diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c index 6611ba0fc9..70d10d68a9 100644 --- a/xen/arch/arm/gic.c +++ b/xen/arch/arm/gic.c @@ -625,6 +625,12 @@ void __cpuinit init_maintenance_interrupt(void) "irq-maintenance", NULL); } +int gic_make_node(const struct domain *d,const struct dt_device_node *node, + void *fdt) +{ + return gic_hw_ops->make_dt_node(d, node, fdt); +} + /* * Local variables: * mode: C diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h index c4daf5ba0d..51a0a26468 100644 --- a/xen/include/asm-arm/gic.h +++ b/xen/include/asm-arm/gic.h @@ -336,9 +336,13 @@ struct gic_hw_operations { unsigned int (*read_apr)(int apr_reg); /* Secondary CPU init */ int (*secondary_init)(void); + int (*make_dt_node)(const struct domain *d, + const struct dt_device_node *node, void *fdt); }; void register_gic_ops(const struct gic_hw_operations *ops); +int gic_make_node(const struct domain *d,const struct dt_device_node *node, + void *fdt); #endif /* __ASSEMBLY__ */ #endif